#ifndef ARP_IMPL_H
#define ARP_IMPL_H

#include <memory>
#include <vector>
#include <array>
#include <unordered_map>

#include "eth_impl.h"
#include "ifconfig.h"
#include "endpoint_addr.h"

namespace usnet {
struct ARPCache4 {
    ARPCache4() = default;
    uint8_t     eth_addr_[6] { };
    uint32_t    hwtype_ { };
    uint32_t    flags_ { };
    uint32_t    mask_ { };
    std::vector<uint32_t> ipaddr_ { };
};

struct ARPCache6 {
    ARPCache6() = default;
    uint8_t     eth_addr_[6] { };
    uint32_t    hwtype_ { };
    uint32_t    flags_ { };
    uint32_t    mask_ { };
    std::vector<std::array<uint8_t, 16>> ipaddr_ { };
};
class ARPImpl {
public:
    ~ARPImpl() = default;

    static std::unique_ptr<ARPImpl> MakeUnique(const Ifconfig* ifcfg, const EndpointAddr* laddr);
    
    bool GetEthAddr(EndpointAddr* addr) const;

private:
    ARPImpl(const Ifconfig* ifcfg, const EndpointAddr* laddr):
        ifcfg_ { ifcfg },
        laddr_ { laddr }
    {
        // nothing to do
    }

    bool InitARPCache();
    bool InitEthImpl();

    const Ifconfig*     ifcfg_ { nullptr };
    const EndpointAddr* laddr_ { nullptr };
    
    std::unordered_map<std::string, ARPCache4> arpcache4_tab_ { };
    std::unordered_map<std::string, ARPCache6> arpcache6_tab_ { };
    std::unique_ptr<EthImpl> eth_impl_ { nullptr };
};
} // end of namespace usnet
#endif